Ext.define("QQWindow",{
	extend:"Ext.container.Container",
	icon:"",
	title:"My QQ Window",
	bodyLayout:"absolute",
	isMax:false,//是否被最大化
	constrain:true,
	minable:false,//是否允许最小化
	maxable:false,//是否允许最大化
	closable:true,//是否允许关闭
	resizable:true,//是否允许改变大小，默认可以改变
	defMinAction:function(e){var id = e.getTarget().id;id = id.substring(0,id.indexOf("_min_bt"));Ext.getCmp(id).hide();},//最小化按钮的响应事件，如果用户没有指定，那么就使用该函数
	defMaxAction:function(e){//最大化按钮的响应事件，如果用户没有指定，那么就使用该函数
		if(!this.isMax){
			var id = e.getTarget().id;
			id = id.substring(0,id.indexOf("_max_bt"));
			this.ow = Ext.getCmp(id).width;
			this.oh = Ext.getCmp(id).height;
			this.ox = Ext.getCmp(id).x;
			this.oy = Ext.getCmp(id).y;
			Ext.getCmp(id).setPosition(0,0);
			Ext.getCmp(id).setSize(Ext.getDoc().getViewSize().width,Ext.getDoc().getViewSize().height);
			document.getElementById(id+"_max_bt").style.background="url(img/tool/btn_restore_normal.png)";
			this.isMax = true;
		}else{
		 	var id = e.getTarget().id;
			id = id.substring(0,id.indexOf("_max_bt"));
			document.getElementById(id+"_max_bt").style.background="url(img/tool/btn_max_normal.png)";
			Ext.getCmp(id).setPosition(this.ox,this.oy);
			Ext.getCmp(id).setSize(this.ow,this.oh);
			this.isMax = false;
		}
	},
	defCloseAction:function(e){var id = e.getTarget().id;id = id.substring(0,id.indexOf("_close_bt"));Ext.getCmp(id).destroy();},//关闭按钮的响应事件，如果用户没有指定，那么就使用该函数
	ox:0,
	oy:0,
	ow:400,
	oh:300,
	background:"img/winBg/default.png",
	width:400,
	height:300,
	initComponent:function(config){
		if(this.minAction==null||typeof(this.minAction)!="function") this.minAction = this.defMinAction;
		if(this.maxAction==null||typeof(this.maxAction)!="function") this.maxAction = this.defMaxAction;
		if(this.closeAction==null||typeof(this.closeAction)!="function") this.closeAction = this.defCloseAction;
		this.items=[];//防止用户使用items与头部重合
		this.ox = this.x;
		this.oy = this.y;
		this.html = "<img src='"+this.background+"' style='width:100%;height:100%'/>";
		var titleHtml="";
		if(Ext.isEmpty(this.icon)) {
			titleHtml=this.title;
		}else {
			titleHtml="<span style='width:21px;height:21px;display:block;float:left;background:url("+this.icon+") no-repeat;'></span><span style='width:"+(this.width-95-30)+"px;height:21px;margin-left:5px;line-height:21px;display:block;float:left'>"+this.title+"</span>";
		}
		if(Ext.isEmpty(this.layout)) this.layout = "absolute";//将当前布局方式改为绝对定位
		if(Ext.isEmpty(this.items)) this.items=[];
		this.floating=true;//Container只有浮动才会显示
		this.header = Ext.create("Ext.container.Container",{id:this.id+"_header",x:0,y:0,width:this.width,height:25,items:[Ext.create("Ext.form.Label",{id:this.id+"_header_title",html:titleHtml,x:5,y:3,width:this.width-95})],layout:"absolute"});
		this.body = Ext.create("Ext.container.Container",{id:this.id+"_body",x:0,y:this.header.height,width:this.width,height:this.height-this.header.height,items:this.bodyItems,layout:this.bodyLayout});
		var tx=0;
		if(this.closable){
			this.header.add(this.createToolLabel(this.id+"_close_bt",360,39,"close",function(e){document.getElementById(this.id).style.background="url(img/tool/btn_close_highlight.png)";},function(e){document.getElementById(this.id).style.background="url(img/tool/btn_close_normal.png)";},function(e){document.getElementById(this.id).style.background="url(img/tool/btn_close_down.png)";},this.closeAction));
			tx+=28;
		}
		if(this.maxable){
			this.header.add(this.createToolLabel(this.id+"_max_bt",360-tx,28,"max",
			function(e){document.getElementById(this.id).style.background=this.isMax?"url(img/tool/btn_restore_highlight.png)":"url(img/tool/btn_max_highlight.png)";},
			function(e){document.getElementById(this.id).style.background=this.isMax?"url(img/tool/btn_restore_normal.png)":"url(img/tool/btn_max_normal.png)";},
			function(e){document.getElementById(this.id).style.background=this.isMax?"url(img/tool/btn_restore_down.png)":"url(img/tool/btn_max_down.png)";},
			this.maxAction));
			tx+=28;
		}
		if(this.minable){
			this.header.add(this.createToolLabel(this.id+"_min_bt",360-tx,28,"min",
			function(e){document.getElementById(this.id).style.background="url(img/tool/btn_mini_highlight.png)";},
			function(e){document.getElementById(this.id).style.background="url(img/tool/btn_mini_normal.png)";},
			function(e){document.getElementById(this.id).style.background="url(img/tool/btn_mini_down.png)";},
			this.minAction));
		}
		this.items.push(this.header,this.body);
		this.draggable={//让头部可以拖动
  			delegate: this.id+"_header"
  		}
  		this.addListener("resize",this.resize);
		Ext.applyIf(this,config);
		this.callParent();
	},
	listeners:{
		click:{
			element:"el",
			fn:function(){
				Ext.WindowManager.bringToFront(this.id);
			}
		}
	},
	setICON:function(icon){
		this.icon=icon;
	},
	getICON:function(){
		return this.icon;
	},
	setTitle:function(title){
		this.title=title;
	},
	getTitle:function(){
		return this.title;
	},
	updateTitle:function(icon,title){
		if(!Ext.isEmpty(icon)) {
			title="<span style='width:21px;height:21px;display:block;float:left;background:url("+icon+") no-repeat;'></span><span style='width:"+(this.width-95-30)+"px;height:21px;margin-left:5px;line-height:21px;display:block;float:left'>"+title+"</span>";
		}
		Ext.getCmp(this.id+"_header_title").update(title);
	},
	resizeChidren:function(){//TO DO 改变子容器的大小 目前在考虑是否需要重写，以及如何重写
		if(!isMax){//如果没有被最大化
			console.log("------!ismax");
		}else{
			console.log("------max");
		}
	},
	getBody:function(){
		return this.body;
	},
	moveChildren:function(){//TO DO 移动子容器的位置 目前在考虑是否需要重写，以及如何重写
		if(!isMax){
			
		}else{
			
		}
	},
	resize:function(cmp,width,height,opts){//改变窗体的大小的响应事件
		this.header.setSize(width,25);
		if(Ext.getCmp(cmp.id+"_min_bt")!=null ) Ext.getCmp(cmp.id+"_min_bt").setPosition(width-(this.ow-Ext.getCmp(cmp.id+"_min_bt").x),0);
		if(Ext.getCmp(cmp.id+"_max_bt")!=null ) Ext.getCmp(cmp.id+"_max_bt").setPosition(width-(this.ow-Ext.getCmp(cmp.id+"_max_bt").x),0);
		if(Ext.getCmp(cmp.id+"_close_bt")!=null ) Ext.getCmp(cmp.id+"_close_bt").setPosition(width-(this.ow-Ext.getCmp(cmp.id+"_close_bt").x),0);
		this.ow = width;
		this.oh = height;
		this.body.setPosition(3,25);
		this.body.setSize(width-6,height-30);
	},
	createToolLabel:function(id,x,width,sig,overHand,outHand,downHand,clickHand){
		var icon="";
		if(sig=="min") icon = "mini";
		if(sig=="max") icon = "max";
		if(sig=="close") icon = "close";
		return Ext.create("Ext.form.Label",{
			id:id,
			x:x,
			y:0,
			width:width,
			height:20,
			style:{
					background:"url(img/tool/btn_"+icon+"_normal.png)"
			},
			listeners:{
				mouseover:{
					element:"el",
					fn:overHand
				},
				mouseout:{
					element:"el",
					fn:outHand
				},
				mousedown:{
					element:"el",
					fn:downHand
				},
				click:{
					element:"el",
					fn:clickHand
				}
			}
		});
	}
});

/*
 树中节点ID标识说明：
 	1、最外面的Main容器的ID是命名方式是：new Date().getTime()_mainContainer,容器ID通常不会使用
 	2、每个子容器（分组容器）的ID命名方式是：groupContainer_id，此ID为这个分组的ID，必须唯一
 	3、每个分组的头部的容器（显示分组名称等）的ID命名方式是：groupHead_id，此ID为这个分组的ID，必须唯一
 	4、每个分组的头部的容器（显示分组名称等）的展开/收缩图标的span的ID命名方式是：groupHead_id_icon，此ID为这个分组的ID，必须唯一
 	5、每个分组的头部的容器（显示分组名称等）的在线/总数统计的span的ID命名方式是：groupHead_id_count，此ID为这个分组的ID，必须唯一
 	6、每个分组的子节点的容器ID的命名方式是：groupChild_id，此ID为这个分组的ID，必须唯一
 	7、每个子节点的容器的命名方式是：cu_id，此ID为这个子节点的ID,必须唯一
 设计说明：
 	1、每个用户的个性图像都有四张：id.jpg、id_h.jpg、id_m.jpg、id_m_h.jpg，这样的话在更改在线状态比较好办，因此从后台传过来的只是一个编号，
 	   实际再根据在线状态生成图像路径
 	2、在ZTreeBase类中有一方法：getGroup()，这个方法是根据分组ID来查询该分组的一些信息，它返回的是一个一维数组，长度为3，其数据信息分别是：
 	   0：这个数据在gf中的下标
 	   1：这个分组当前展开/收缩状态
 	   2：这个分组容器的高度
 	   3:这个分组上次展开时的历史高度
 	3、在ZTreeBase类中，有个非常重要的属性：gf，这个属性是groupFriend缩写，是用来存储每个分组的相关信息，它是一个JSON格式数据，为数组，每个对象有以下几个属性：
 	  1、id 分组ID
 	  2、flag 分组是否展开的标记 0为收缩 1为展开
 	  3、height 分组容器的高度 默认情况下为30，也就是头部的高度，当加载分组数据加载完毕时会自动更改其高度
 	  4、oldHeight 上一次执行收缩/展开时的高度，这个属性主要是为了避免分组数据加载较慢，而用户在收缩或展开分组时出现高度不对的问题
 	  5、load 这个分组是否已经加载完毕，默认为0 0未加载 1已加载完毕
*/
Ext.define("ZTreeBase",{
	extend:"Ext.container.Container",
	gf:[],//用来存储每个组是否展开的标记JSON
	mainHeight:0,
	constructor:function(){
		return this;
	},
	createGroup:function(childUrl,data,mainId,mainX,mainY,mainWidth){
		this.groupWidth = mainWidth;
		this.mainCon=this.createContainer(new Date().getTime()+"_mainContainer",mainX,mainY,mainWidth,this.mainHeight,"vbox");
		if(typeof(data)=="object"&&data.length>0){
			var json = "";
			this.mainHeight = 30*data.length;
			this.mainCon.setHeight(this.mainHeight);
			for(var i=0;i<data.length;i++){//先将所有分组加载完成
				json+=",{\"id\":"+data[i]["id"]+",\"flag\":0,\"height\":30,\"oldHeight\":30,\"load\":0}";
				var groupCon = this.createContainer("groupContainer_"+data[i]["id"],0,0,mainWidth,30,"absolute");
				var groupHead = this.createGroupHead("groupHead_"+data[i]["id"],mainWidth,30,data[i]["groupname"]);
				var childrenCon = this.createContainer("groupChild_"+data[i]["id"],30,30,mainWidth-30,0,"vbox");
				groupCon.add(groupHead);
				groupCon.add(childrenCon);
				this.mainCon.add(groupCon);
			}
			json = "["+json.substring("1")+"]";
			this.gf = eval(json);
			for(var i=0;i<data.length;i++){//第二步：加载每个分组下的好友
				this.loadChildren(childUrl,data[i]["id"]);//加载一个分组下的好友
			}
		}
		return this.mainCon;
	},
	createContainer:function(id,x,y,width,height,layout,autoScroll){//创建窗口
		return new Ext.container.Container({
			id:id,
			x:x,
			y:y,
			width:width,
			height:height,
			layout:layout
		});
	},
	createGroupHead:function(id,width,height,text){//创建好友容器的头部
		var obj = this;
		return new Ext.form.Label({
			id:id,
			x:10,
			y:0,
			width:width-10,
			height:height,
			html:"<span id='"+id+"_icon' style='display:block;margin-top:9px;width:12px;height:11px;float:left;background:url(./img/tool/expand.gif)'></span>&nbsp;<span style='display:block;height:30px;line-height:30px;float:left;'>&nbsp;"+text+"</span><span style='display:block;height:30px;line-height:30px;float:left;' id='"+id+"_count'>(0/0)</span>",
			style:{
				cursor:"pointer",
				display:"block"
			},
			listeners:{
				click: {
		            element: 'el',
		            fn: function(e){//单击的监听事件
				          var tid = id.substring(id.indexOf("_")+1);
				          var data = obj.getGroup(tid);
				          if(data[1]==0){//展开节点
				          	 if(obj.gf[data[0]]["load"]==1){
				          	 	 if(data[3]==30){//解决第一次打开时有问题
				          	 	 	data[3] = data[2];
				          	 	 	obj.gf[data[0]]["oldHeight"]=data[2];//替换历史高度
				          	 	 }
				          	 	 obj.mainHeight += (data[3]-30);//更改整个容器的高度属性
								 obj.mainCon.setHeight(obj.mainHeight);//更改整个容器的高度属性
					          	 obj.expand(tid);
				          	 }
				          	 obj.gf[data[0]]["flag"]=1;
				          	 document.getElementById(id+"_icon").style.background="url(./img/tool/collapse.gif)";
				          }else{//收缩节点
				          	if(obj.gf[data[0]]["load"]==1){
					          	obj.mainHeight -= (data[3]-30);//更改整个容器的高度属性
								obj.mainCon.setHeight(obj.mainHeight);//更改整个容器的高度属性
					          	obj.collapse(tid);
					            obj.gf[data[0]]["oldHeight"]=data[2];//替换历史高度
				            }
				            obj.gf[data[0]]["flag"]=0;
				            document.getElementById(id+"_icon").style.background="url(./img/tool/expand.gif)";
				          }
				     }
   				},
   				contextmenu:{
   					element:"el",
   					fn:function(e,t,o,opts){
   	   					e.stopEvent();
   	   					ListWindowHandler.groupContextMenu(e,t,o,{gid:id});
   	   				}
   				}
			}
		});
	},
	expand:function(id){//展开一个节点
		Ext.getCmp("groupChild_"+id).show();
		Ext.getCmp("groupContainer_"+id).setSize(this.groupWidth,this.getGroup(id)[2]);
	},
	collapse:function(id){//收缩一个节点
		Ext.getCmp("groupChild_"+id).hide();
		Ext.getCmp("groupContainer_"+id).setSize(this.groupWidth,30);
	},
	loadChildren:function(url,id){//加载一个分组下的好友
		var obj = this;
		Ext.Ajax.request({
			url:url,
			params:{
				gid:id
			},
			method:"post",
			success:function(response,opts){
				try{
					var data = eval(response.responseText);
				}catch(msg){
					Ext.Msg.alert("错误","服务器返回数据错误!");
					return;
				}
				if(typeof(data)=="object"&&data.length>0){
					var group = obj.getGroup(id);
					obj.gf[group[0]]["height"]+=data.length*50;//更改一个分组容器的高度
					obj.gf[group[0]]["load"]=1;;//更改分组的加载状态
					Ext.getCmp("groupChild_"+id).setHeight(data.length*50);//更改子节点容器的高度
					Ext.getCmp("groupChild_"+id).hide();//隐藏子节点容器的高度
					var onlineNum=0;
					for(var i=0;i<data.length;i++){
						if(data[i]["online"]==1) onlineNum++;//将在线人数++
						Ext.getCmp("groupChild_"+id).add(obj.createChildLabel(id,data[i]["uid"],obj.groupWidth-30,data[i]["icon"],data[i]["nickname"],data[i]["signature"],data[i]["online"]));
					}
					Ext.getCmp("groupContainer_"+id).options={online:onlineNum,total:data.length};
					document.getElementById("groupHead_"+id+"_count").innerHTML="("+onlineNum+"/"+data.length+")";//更改在线人数统计
				}
			}
		});
	},
	createChildLabel:function(gid,id,width,icon,name,signature,online){//创建一个用户的信息的container
		var sicon = (parseInt(online)==UserStatus.OFFLINE||parseInt(online)==UserStatus.INVISIBLE)?"./img/info/"+icon+"_h.jpg":"./img/info/"+icon+".jpg";
		var minSIcon = (parseInt(online)==UserStatus.OFFLINE||parseInt(online)==UserStatus.INVISIBLE)?"./img/info/"+icon+"_m_h.jpg":"./img/info/"+icon+"_m.jpg";
		var con =  new FriendContainer({
			id:"cu_"+id,
			width:width,
			height:50,
			layout:"absolute",
			uid:id,
			nickname:name,
			icon:icon,
			signature:signature,
			online:online,
			groupId:gid,
			items:[
				{//显示图像的label
					xtype:"label",
					id:"cu_"+id+"_icon",
					x:5,
					y:5,
					width:40,
					height:40,
					html:"<img src='"+sicon+"' style='width:38px;height:38px;'/>",
					style:{
						border:"1px solid #8DD7F4",
						cursor:"pointer"
					}
				},{//显示名字的label
					xtype:"label",
					id:"cu_"+id+"_name",//修改过 2012-10-3 20:27 为方便收到消息时获取发送人
					x:50,
					y:5,
					width:width-50,
					height:20,
					html:name+"("+id+")"
				},{//显示签名的label
					xtype:"label",
					x:50,
					y:25,
					width:width-50,
					height:20,
					html:signature.ellipsis(28)
				}
			],
			listeners:{
				mouseover:{//当鼠标移动到用户的label上时，将当前label背景颜色改变
					element:"el",
					fn:function(e){
						document.getElementById("cu_"+id).style.backgroundColor="#CCE2F6";
					}
				},
				mouseout:{//当鼠标移动开用户的label上时，将当前label背景颜色还原
					element:"el",
					fn:function(e){
						document.getElementById("cu_"+id).style.backgroundColor="";
					}
				},
				dblclick:{//双击事件
					element:"el",
					fn:function(){
						ListWindowHandler.openChatWin(id,name,minSIcon);
					}
				},
				contextmenu:{
					element:"el",
					fn:function(e,t,o,opts){
						e.stopEvent();
						ListWindowHandler.userContextMenu(e,t,o,{id:id,gid:gid});
					}
				}
			}
		});
		con.updateStatus(online);
		return con;
	},
	getGroup:function(id){//根据ID查找一个组的展开与收缩的FLAG
		for(var i=0;i<this.gf.length;i++){
			if(this.gf[i]["id"]==id){
				return [i,this.gf[i]["flag"],this.gf[i]["height"],this.gf[i]["oldHeight"]];
			}
		}
		return null;
	}
});
Ext.define("ZTree",{
	extend:"ZTreeBase",
	config:{
		method:"post",
		url:"/",
		childUrl:"/"
	},
	constructor:function(config){
		this.initConfig(config);
 				return this;
 			},
 			loadGroup:function(cmp,id,x,y,width,height){
 				var obj = this;
 				Ext.Ajax.request({
  				url:this.config.url,
  				method:this.config.method,
  				success:function(response,opts){
  					try{
  						var data = eval(response.responseText);
  					}catch(msg){
  						Ext.Msg.alert("错误","服务器返回数据错误！");
  						return;
  					}
  					cmp.removeAll();
  					cmp.add(obj.createGroup(obj.childUrl,data,id,x,y,width,height));
  				}
 				});
 			}
});

/**
 * 显示一个用户信息的的容器
 * 继承自Ext.container.Container
 * 1、添加了6个属性 uid 用户的UID  nickname 用户的昵称 icon 用户的图像编号  signature 用户的个性签名 groupid 好友所在分组ID
 * 2、添加了方法updateStatus,用来更新一个用户的在线状态
 */
Ext.define("FriendContainer",{
	extend:"Ext.container.Container",
	uid:null,
	nickname:null,
	icon:null,
	signature:null,
	online:0,
	groupId:0,
	listeners:{
		destroy:function(){
			alert("我被销毁了");//TODO 此处需要更新整个窗口、分组容器的高度
		}
	},
	initComponent:function(config){//不做任何事，只实现方法
		Ext.applyIf(this,config);
		this.callParent();
	},
	updateStatus:function(online){
		var icon = (online==0||online==4)?this.icon+"_h":this.icon;
		var labs = this.query("label");
		labs[0].update("<img src='./img/info/"+icon+".jpg'style='width:38px;height:38px;'/>");
		var lastSta = this.online;
		this.online=online;
		var opts = Ext.getCmp("groupContainer_"+this.groupId).options;
		switch(this.online){
		case UserStatus.ONLINE:
			var labs = this.query("label");
			if(labs.length>3){
				for(var i=3;i<labs.length;i++){
					this.remove(labs[i].id);
				}
			}
			if(opts!=undefined){//页面加载用户列表时会调用一次这个方法，因此会为undefined
				if(lastSta==0||lastSta==4){
					opts.online+=1;
				}
				document.getElementById("groupHead_"+this.groupId+"_count").innerHTML = "("+opts.online+"/"+opts.total+")";
			}
			break;
		case UserStatus.OFFLINE:
			var labs = this.query("label");
			if(labs.length==4){
				for(var i=3;i<labs.length;i++){
					this.remove(labs[i].id);
				}
			}
			if(opts!=undefined){//页面加载用户列表时会调用一次这个方法，因此会为undefined
				opts.online-=1;
				document.getElementById("groupHead_"+this.groupId+"_count").innerHTML = "("+opts.online+"/"+opts.total+")";
			}
			break;
		case UserStatus.INVISIBLE:
			var labs = this.query("label");
			if(labs.length==4){
				for(var i=3;i<labs.length;i++){
					this.remove(labs[i].id);
				}
			}
			if(lastSta!=0&&lastSta!=4){
				opts.online-=1;
				document.getElementById("groupHead_"+this.groupId+"_count").innerHTML = "("+opts.online+"/"+opts.total+")";
			}
			break;
		case UserStatus.BUSY:
			this.add(Ext.create("Ext.form.Label",{
				x:5,
				y:5+40-11,
				width:11,
				height:11,
				style:{
					background:"url(./img/status/busy.png)"
				}
			}));
			if(lastSta==0||lastSta==4){
				opts.online+=1;
				document.getElementById("groupHead_"+this.groupId+"_count").innerHTML = "("+opts.online+"/"+opts.total+")";
			}
			break;
		case UserStatus.AWAY:
			this.add(Ext.create("Ext.form.Label",{
				x:5,
				y:5+40-11,
				width:11,
				height:11,
				style:{
					background:"url(./img/status/away.png)"
				}
			}));
			if(lastSta==0||lastSta==4){
				opts.online+=1;
				document.getElementById("groupHead_"+this.groupId+"_count").innerHTML = "("+opts.online+"/"+opts.total+")";
			}
			break;
		default:
				break;
		}
	}
});

/**
 * 定义自己的消息提示窗体，
 * 继承自Ext.container.Container，
 * 1、新增了msgcount属性，用户记录当前有多少条未读消息
 * 2、新增了addNewMsg方法，用来添加一个未读消息记录
 */
Ext.define("MsgNoticeWindow",{
	extend:"Ext.container.Container",
	msgcount:0,
	msgs:[],
	initComponent:function(config){
		this.id = "MSGWINDOW";
		this.width = 150;
		this.layout="vbox";
		this.floating=true;
		this.msgs = new Array();
		Ext.applyIf(this,config);
		this.callParent();
	},
	addNewMsg:function(mess,icon,nickname){//TODO 需要修改
		if(!this.isExist(mess["from"])){
			var obj = this;
			this.msgcount++;
			console.log("开始编码："+"{\"id\":"+mess["from"]+",\"msgs\":[]}");
		    var data = Ext.JSON.decode("{\"id\":"+mess["from"]+",\"msgs\":[]}");
		    console.log("编码结束");
		    data["msgs"].push(Ext.JSON.encode(mess));
		    this.msgs.push(data);
			var lab = new Ext.form.Label({
				width:150,
				height:25,
				html:"<div style='width:25px;float:left;'><img src='./img/info/"+icon+".jpg' style='width:23px;height:23px;'/></div><div style='width:125px;height:25px;float:left;line-height:25px;'>"+nickname+"</div>",
				style:{
					cursor:"pointer"
				},
				listeners:{
					click:{
						element:"el",
						fn:function(e){
							if(obj.msgcount>0){
								obj.remove(this.id);
								obj.msgcount--;
								obj.hide();
								var cw = Ext.getCmp("cw_"+mess["from"]);
								if(cw==null){//没有创建窗体
									var title = "与["+nickname+"]聊天中";
									ListWindowHandler.openChatWin(mess["from"],nickname,"./img/info/"+icon+"_m.jpg");
									var service = new MessageHandleService();
									for(var i=0;i<obj.getMsg(mess["from"]).length;i++){
										var om = Ext.JSON.decode(obj.getMsg(mess["from"])[i]);
										var msg = om["msg"];
										var time = om["time"];
										Ext.getCmp("cw_"+mess["from"]+"_rw").setText(document.getElementById("cw_"+mess["from"]+"_rw").innerHTML+service.formatMsg(mess["from"],time,msg),false);
									}
									Ext.get("cw_"+mess["from"]+"_rw").scroll("bottom",document.getElementById("cw_"+mess["from"]+"_rw").innerHTML.length,false);//滚动至底部
									Ext.get("cw_"+mess["from"]+"_rw").scroll("right",document.getElementById("cw_"+mess["from"]+"_rw").innerHTML.length,false);//滚动至左部
									Ext.getCmp("cw_"+mess["from"]+"_ww").focus();
								}else{//窗体已经创建
									if(cw.isHidden()){//如果窗体是隐藏(关闭着的)
										var service = new MessageHandleService();
										for(var i=0;i<obj.getMsg(mess["from"]).length;i++){
											var om = Ext.JSON.decode(obj.getMsg(mess["from"])[i]);
											var msg = om["msg"];
											var time = om["time"];
											Ext.getCmp("cw_"+mess["from"]+"_rw").setText(document.getElementById("cw_"+mess["from"]+"_rw").innerHTML+service.formatMsg(mess["from"],time,msg),false);
										}
										Ext.get("cw_"+mess["from"]+"_rw").scroll("bottom",document.getElementById("cw_"+mess["from"]+"_rw").innerHTML.length,false);//滚动至底部
										Ext.get("cw_"+mess["from"]+"_rw").scroll("right",document.getElementById("cw_"+mess["from"]+"_rw").innerHTML.length,false);//滚动至左部
										Ext.getCmp("cw_"+mess["from"]+"_ww").focus();
										cw.show();
									}
								}
								obj.removeMsg(mess["from"]);
							}
						}
					},
					mouseover:{
						element:"el",
						fn:function(e){
							document.getElementById(this.id).style.backgroundColor='#C3F2FC';
						}
					},
					mouseout:{
						element:"el",
						fn:function(e){
							document.getElementById(this.id).style.backgroundColor='#fff';
						}
					}
				}
			});
			this.setHeight(this.msgcount*25);
			this.add(lab);
		}else{
			this.addMsg(mess["from"],mess);
		}
	},
	isExist:function(id){
		for(var i=0;i<this.msgs.length;i++){
			if(this.msgs[i]["id"]==id) return true;
		}
		return false;
	},
	getMsg:function(id){
		for(var i=0;i<this.msgs.length;i++){
			if(this.msgs[i]["id"]==id) return this.msgs[i]["msgs"];
		}
		return "";
	},
	addMsg:function(id,mess){
		for(var i=0;i<this.msgs.length;i++){
			if(this.msgs[i]["id"]==id) this.msgs[i]["msgs"].push(Ext.JSON.encode(mess));
		}
	},
	removeMsg:function(id){
		for(var i=0;i<this.msgs.length;i++){
			if(this.msgs[i]["id"]==id) this.msgs.splice(i,1);
		}
	}
});

Ext.define("MsgWindow",{
	statics:{
		alert:function(x,y,width,msg){
			new Ext.container.Container({
				x:x,
				y:y,
				width:width,
				height:25,
				floating:true,
				html:"<div style='height:23px;line-height:23px;'>"+msg+"</div>",
				style:{
					backgroundColor:"#fff",
					border:"1px solid #C0C0C0",
					borderRadius:"3px"
				},
				listeners:{
					show:{
						fn:function(cmp,opts){
							var task = new Ext.util.DelayedTask(function(){
						    	cmp.destroy();
						    });
							task.delay(1500);
						}
					}
				}
			}).show();
		},
		/**
		 * 弹出一个带有要求用户自己填写信息的提示框，有一个确认和一个取消按键
		 * @param {int} x 显示的位置X
		 * @param {int} y 显示的位置Y
		 * @param {String} title 标题
		 * @param {String} problem 询问内容
		 * @param {Function} callback 回调函数，共有两个参数，一个是ok/cancel，另外一个是Ext.form.field.Base
		 */
		prompt:function(x,y,title,problem,callback){
			var input = new Ext.create("Ext.form.field.Base",{
				margin:10,
				fieldStyle:{
			 		width:"220px"
				}
			});
			var win = new QQWindow({
				x:x,
				y:y,
				width:250,
				height:120,
				bodyLayout:"auto",
				resizable:false,
				shadow:"frame",
				modal:true,
				bodyItems:[
				  {
					  xtype:"label",
					  width:this.width,
					  text:problem,
					  margin:"40 10 10 10"
				  },input,{
					  margin:"0 0 0 45",
					  xtype:"button",
					  width:70,
					  text:"确&nbsp;认",
					  handler: Ext.Function.bind(callback,this,["ok",input]),
					  listeners:{
						  click:{
							  element:"el",
							  fn:function(){
								 win.destroy();
							  }
						  }
					  }
				  },{
					  margin:"0 0 0 10",
					  xtype:"button",
					  width:70,
					  text:"取&nbsp;消",
					  handler: Ext.Function.bind(callback,this,["cancel",input]),
					  listeners:{
						  click:{
							  element:"el",
							  fn:function(){
								 win.destroy();
							  }
						  }
					  }
				  }
				],
				title:title
			});
			win.show();
			return win;
		}
	}
});

/**
 * 显示当前在线状态的label，继承自Ext.form.Label，为其新增了status属性和updateStatus()方法
 */
Ext.define("StatusLabel",{
	extend:"Ext.form.Label",
	defStatus:"online",
	initComponent:function(config){
		if(this.status==null||this.status==undefined){
			this.status = this.defStatus;
		}
		this.html = "<div><span style='width:13px;height:12px;margin-top:4px;display:block;float:left;'><img src='img/status/"+this.status+".png'/></span><span style='width:30px;height:20px;line-height:18px;display:block;float:left'>"+UserStatus.transformStatusToText(this.status)+"</span></div>";
		Ext.applyIf(this,config);
		this.callParent();
	},
	updateStatus:function(status){
		this.status = status;
		this.update("<div><span style='width:13px;height:12px;margin-top:4px;display:block;float:left;'><img src='img/status/"+this.status+".png'/></span><span style='width:30px;height:20px;line-height:18px;display:block;float:left'>"+UserStatus.transformStatusToText(this.status)+"</span></div>");
	}
});

/**
 * 覆盖HtmlEditor，为其添加keydown、keyup、keypress事件
 * 注：改动来自互联网，原作者信息如下：
 * author: hoojo 
 * email: hoojo_@126.com 
 * blog: http://blog.csdn.net/IBM_hoojo 
 */
Ext.override(Ext.form.HtmlEditor, {
	initEditor : function() {
		var dbody = this.getEditorBody();
		var ss = this.el.getStyles('font-size', 'font-family',
				'background-image', 'background-repeat');
		ss['background-attachment'] = 'fixed'; // w3c  
		ss['background-color'] = 'white';
		dbody.bgProperties = 'fixed'; // ie  
		Ext.core.DomHelper.applyStyles(dbody, ss);
		if (this.doc) {
			try {
				Ext.EventManager.removeAll(this.doc);
			} catch (e) {
			}
		}
		this.doc = this.getDoc();
		Ext.EventManager.on(this.doc, {
			'mousedown' : this.onEditorEvent,
			'dblclick' : this.onEditorEvent,
			'click' : this.onEditorEvent,
			'keyup' : this.onEditorKeyUpEvent,
			'keydown' : this.onEditorKeyDownEvent,
			'keypress' : this.onEditorKeyPressEvent,
			buffer : 100,
			scope : this
		});
		if (Ext.isGecko) {
			Ext.EventManager.on(this.doc, 'keypress',
					this.applyCommand, this);
		}
		if (Ext.isIE || Ext.isSafari || Ext.isOpera) {
			Ext.EventManager
					.on(this.doc, 'keydown', this.fixKeys, this);
		}
		this.initialized = true;
		this.fireEvent('initialize', this);
		this.doc.editorInitialized = true;
		this.pushValue();
	},
	initComponent : function() {
		this.addEvents('initialize', 'activate', 'beforesync',
				'beforepush', 'sync', 'push', 'editmodechange',
				'keydown', 'keyup', 'keypress');
	},
	onEditorKeyPressEvent : function(e) {
		this.updateToolbar();
		this.fireEvent("keypress", this, e);
	},
	onEditorKeyUpEvent : function(e) {
		this.updateToolbar();
		this.fireEvent("keyup", this, e);
	},
	onEditorKeyDownEvent : function(e) {
		this.updateToolbar();
		this.fireEvent("keydown", this, e);
	}
});


